﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Linq.Expressions;

namespace JXT.PrimaryKey.Batman.Reflection
{
    /// <summary>
    /// 反射扩展方法
    /// </summary>
    public static class ReflectionExtensions
    {
        /// <summary>
        /// 获取指定方法的快速执行委托
        /// </summary>
        /// <param name="method">方法对象</param>
        /// <returns>执行委托</returns>
        public static Func<object, object[], object> GetLambdaInvoker(this MethodInfo method)
        {
            if (method == null)
                throw new ArgumentNullException("method");
            var instanseParameter = Expression.Parameter(typeof(object), "instanse");
            var parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
            IList<Expression> parametersExpression = new List<Expression>();
            ParameterInfo[] parameters = method.GetParameters();
            for (int i = 0; i < parameters.Length; i++)
            {
                var parameterExpression = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));
                var convertParameterExpression = Expression.Convert(parameterExpression, parameters[i].ParameterType);
                parametersExpression.Add(convertParameterExpression);
            }
            var convertInstanseExpression = method.IsStatic ? null : Expression.Convert(instanseParameter, method.ReflectedType);
            var callExpress = Expression.Call(convertInstanseExpression, method, parametersExpression);
            if (method.ReturnType == typeof(void))
            {
                Expression<Action<object, object[]>> lambda = Expression.Lambda<Action<object, object[]>>(callExpress, instanseParameter, parametersParameter);
                var action = lambda.Compile();
                return (instanse, args) =>
                {
                    action(instanse, args);
                    return null;
                };
            }
           
            {
                var convertResultExpress = Expression.Convert(callExpress, typeof(object));
                Expression<Func<object, object[], object>> lambda = Expression.Lambda<Func<object, object[], object>>(
                    convertResultExpress, instanseParameter, parametersParameter);
                return lambda.Compile();
            }
        }

        /// <summary>
        /// 获取指定方法的高级方法对象
        /// </summary>
        /// <param name="method">方法对象</param>
        /// <returns>Lambda方法对象</returns>
        public static LambdaMethodInfo GetLambdaMethodInfo(this MethodInfo method)
        {
            return new LambdaMethodInfo(method);
        }

        /// <summary>
        /// 获取指定属性的高级属性对象
        /// </summary>
        /// <param name="property">属性对象</param>
        /// <returns>Lambda属性对象</returns>
        public static LambdaPropertyInfo GetLambdaPropertyInfo(this PropertyInfo property)
        {
            return new LambdaPropertyInfo(property);
        }

        public static bool CastableAs<T>(this Type type)
        {
            return typeof(T).IsAssignableFrom(type);
        }

        public static Type GetType<T>(this string typeName)
        {
            Type type;
            if (string.IsNullOrEmpty(typeName)) return null;
            try
            {
                type = Type.GetType(typeName);
                if (type == null) throw new Exception(string.Format("Unable to find type {0}", typeName));
            }
            catch (Exception exception)
            {
                throw new Exception(string.Format("Unable to find type {0}: {1}", typeName, exception.Message), exception);
            }
            if (!type.CastableAs<T>()) throw new Exception(string.Format("{0} cannot be cast as {1}.", type.Name, typeof(T).Name));
            return type;
        }


    }
}
